#pragma once

#include <vector>
#include <thread>
#include <memory>
#include "unistd.h"
#include "include/TcpSocket.hpp"
#include "include/Log.hpp"
#include "Common.hpp"
#include "ConnectionFactory.hpp"
#include "EventHandler.hpp"

static const int default_thread_num = 3;
static std::string loop_back_ip = "127.0.0.1";
static const uint16_t default_port_start = 4090;

class SubReactors
{
public:
    SubReactors(int threadNum = default_thread_num, uint16_t portStart = default_port_start): _threadNum(threadNum)
    {
        for(int i = 0; i < _threadNum; i++)
        {
            log.message(INFO, "createReactorThread, id: %d, port: %d", i, portStart);
            createReactorThread(portStart++);
        }
    }

    void createReactorThread(int port)
    {
        // 创建线程
        Socket* threadListenSock = new TcpSocket();
        threadListenSock->createListenSocket(port);
        setNonBlock(threadListenSock->getSocketFd());
        _threads.emplace_back(std::thread(threadRoutine, threadListenSock));

        // 对线程发起连接
        Socket* connSock = new TcpSocket();
        connSock->createConnectSocket(loop_back_ip, port);
        setNonBlock(connSock->getSocketFd());
        _connFds.push_back(connSock->getSocketFd());
    }

    void addConnectionToReactor(Reactor* reactor)
    {
        reactor->setConnFds(_connFds);
        for(int i = 0; i < _connFds.size(); i++)
        {
            auto reader = std::bind(&EventHandler::read, std::placeholders::_1);
            auto writer = std::bind(&EventHandler::write, std::placeholders::_1);
            auto excepter = std::bind(&EventHandler::except, std::placeholders::_1);
            reactor->addSubReactorConnection(ConnectionFactory::createNormalConnection(
                _connFds[i], reader, writer, excepter, EPOLLIN|EPOLLET, reactor));
        }
    }
    
    ~SubReactors()
    {}
private:
    static void threadRoutine(Socket* listen_sock)
    {
        std::unique_ptr<Reactor> reactor = std::make_unique<Reactor>();

        auto reader = std::bind(&EventHandler::acceptForSelf, std::placeholders::_1);

        reactor->addConnection(ConnectionFactory::createListenConnection(
            listen_sock->getSocketFd(), reader, EPOLLIN|EPOLLET, reactor.get()));

        reactor->start();
    }
private:
    int _threadNum;
    std::vector<std::thread> _threads;
    std::vector<int> _connFds;
};